﻿using System;
using System.Collections.Generic;
using System.Linq;
using Sustainalytics.Reporting.Framework;
using Foxit.PDF.PageElements;
using Foxit.PDF;
using Sustainalytics.Entities;
using Sustainalytics.Utils;

namespace Sustainalytics.Governance.Reporting
{
    public class IssuesSection: PdfReportSectionGenerator
    {
        public override void ComposeSectionContent()
        {
            const string sectionTitle = "Key Corporate Governance Issues";
            const float titleFontSize = 16f;
            const float sectionTitleHeight = 22f;
            float top = 20.0f;

            var style = new FormattedTextAreaStyle(Fonts.CalibriFontFamily, 9f, false)
            {
                Paragraph = { Align = TextAlign.Justify, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false }
            };


            var width = _report.PageMaxWidth;
            var height = _report.PageMaxHeight - 25f;

            var table = GetDefaultTable(_report.LeftMargin, top, width, height);


            table.Columns.Add(width);

            var row = table.Rows.Add(sectionTitleHeight);

            
            var text = string.Format("<p><font color='FFFFFF'><b>{0}</b></font></p>", sectionTitle);
            var cell = row.Cells.Add(new FormattedTextArea(text, 5f, 1f, width, titleFontSize + 2f, Fonts.CalibriFontFamily, titleFontSize, false));
            cell.BackgroundColor = Colors.SectionColor;
            cell.VAlign = VAlign.Center;

            row = table.Rows.Add(EmptyRowHeight);
            row.Cells.Add(string.Empty);

            var pageNumber = 1;
            var page = _report.NewPage();
            _report.Pages.Add(page);
            page.Elements.Add(table);

            top += table.GetRequiredHeight() + 10f;

            if (_dataSource.Issues.Any())
            {
                foreach (var issue in _dataSource.Issues.OrderBy(i => i.Number))
                {
                    issue.Score = 0;

                    var issuesPerformance = _dataSource.IssuesPerformance.SingleOrDefault(i => i.Number == issue.Number);
                    if (issuesPerformance != null)
                    {
                        issue.Score = ScoreConversion.GetRoundedScore(issuesPerformance.Score);
                    }

                    var issueTable = AddIssueTable(issue, _dataSource.CompanyProfile.FullProfile);
                    var issueHeight = issueTable.GetRequiredHeight();

                    if (top + issueHeight > _report.PageMaxHeight - 25f)
                    {
                        page = _report.NewPage();
                        _report.Pages.Add(page);
                        top = 20.0f;
                        pageNumber++;
                    }

                    var verticalPosition = top + 73;
                    
                    issueTable.X = _report.LeftMargin;
                    issueTable.Y = top;

                    page.Elements.Add(issueTable);
                    top += issueHeight;


                    if (_dataSource.CompanyProfile.FullProfile)
                    {
                        var comment = GetComment(issue);

                        var formattedTextArea = new FormattedTextArea(comment, 0.0f, 0.0f, width, 500f, style);
                        var commentHeight = formattedTextArea.GetRequiredHeight() + 20f;

                        verticalPosition += commentHeight + 43f;
                    }

                    _pageElementPositions.Add(new PageElementPosition
                    {
                        Id = issue.Id,
                        Name = issue.Name,
                        PageNumber = pageNumber,
                        HorizontalPosition = _report.LeftMargin,
                        VerticalPosition = verticalPosition,
                        Height = 14f,
                        Width = 75f
                    });
                }
            }
        }

        private string GetComment(GovernanceIssue issue)
        {
            var comment = string.Empty;
            if (!string.IsNullOrWhiteSpace(issue.Comment))
            {
                comment = issue.Comment
                    .Replace("<div>", "<p>")
                    .Replace("</div>", "</p>")
                    .Replace("<div />", "</p>")
                    .Replace("<br />", "</p><p>");

                comment = HTMLConvertor.ConvertComment(comment);
            }

            return comment;
        }

        private Table AddIssueTable(GovernanceIssue issue, bool showOutlook)
        {
            const float issueFontSize = 16f;
            const float issueTitleHeight = 20f;

            var style = new FormattedTextAreaStyle(Fonts.CalibriFontFamily, 9f, false)
            {
                Paragraph = { Align = TextAlign.Justify, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false }
            };

            var width = _report.PageMaxWidth;

            var table = GetDefaultTable(0.0f, 0.0f, width, issueTitleHeight);
            
            table.Columns.Add(width * 0.3f);
            table.Columns.Add(width * 0.7f);

            var row = table.Rows.Add(issueTitleHeight);

            var cell = row.Cells.Add(
                new Label(issue.Name, 0.0f, 0.0f, width,
                    issueFontSize + 2f, Fonts.CalibriBold, issueFontSize), 2);
            cell.Border.Bottom.LineStyle = LineStyle.Solid;
            cell.Border.Bottom.Width = 1.5f;
            cell.Border.Bottom.Color = RgbColor.Black;

            if (showOutlook)
            {
                var comment = GetComment(issue);

                var formattedTextArea = new FormattedTextArea(comment, 0.0f, 0.0f, width, 500f, style);
                var commentHeight = formattedTextArea.GetRequiredHeight() + 20f;

                formattedTextArea = new FormattedTextArea(comment, 0.0f, 0.0f, width, commentHeight, style);

                row = table.Rows.Add(commentHeight);
                cell = row.Cells.Add(formattedTextArea, 2);
                cell.Padding.Top = 15f;
            }
            else
            {
                row = table.Rows.Add(EmptyRowHeight);
                row.Cells.Add(string.Empty);
            }

            var issueBullets = AddIssueBullets(issue, showOutlook, width * 0.3f);
            var rowHeight = issueBullets.GetRequiredHeight();


            var issueIndicators = issue.Indicators.OrderBy(i => Convert.ToInt32(i.Number.Substring(5))).ToList();

            var indicators = AddIndicators(issueIndicators, width * 0.7f);
            var indicatorsHeight = issueBullets.GetRequiredHeight();

            if (indicatorsHeight > rowHeight) rowHeight = indicatorsHeight;

            row = table.Rows.Add(rowHeight);
            row.Cells.Add(issueBullets);
            row.Cells.Add(indicators);

            row = table.Rows.Add(EmptyRowHeight);
            row.Cells.Add(string.Empty);

            var requiredHeight = table.GetRequiredHeight();
            table.Height = requiredHeight;

            return table;
        }

        private Table AddIssueBullets(GovernanceIssue issue, bool showOutlook, float width)
        {
            const float fontSize = 12f;
            const float radius = 14f;

            const float bulletHeight = radius*2;
            const float height = bulletHeight*3;

            var table = GetDefaultTable(0.0f, 0.0f, width, height);

            table.Columns.Add(50f);
            table.Columns.Add(50f);


            var row = table.Rows.Add(bulletHeight);
            var cell = row.Cells.Add(new Label("Score", 0.0f, 2.0f, width,
                    fontSize + 2f, Fonts.CalibriBold, fontSize));
            cell.VAlign = VAlign.Center;

            row.Cells.Add(new BulletScore
            {
                Top = 0.0f,
                Left = bulletHeight / 2 - radius,
                Radius = radius,
                Value = issue.Score.ToString(),
                ValueFont = Fonts.CalibriBold,
                ValueFontSize = 14f
            });

            row = table.Rows.Add(EmptyRowHeight);
            row.Cells.Add(string.Empty);

            if (showOutlook && issue.Outlook.HasValue)
            {
                row = table.Rows.Add(bulletHeight);
                
                cell = row.Cells.Add(new Label("Outlook", 0.0f, 2.0f, width,
                    fontSize + 2f, Fonts.CalibriBold, fontSize));
                cell.VAlign = VAlign.Center;

                row.Cells.Add(new BulletOutlook
                {
                    Top = 0.0f,
                    Left = bulletHeight/2 - radius,
                    Radius = radius,
                    Value = (int) issue.Outlook.Value
                });

                row = table.Rows.Add(EmptyRowHeight);
                row.Cells.Add(string.Empty);
            }

            row = table.Rows.Add(bulletHeight);
            row.Cells.Add(new Label("See Full Analysis", 0.0f, 0.0f, width,
                fontSize, Fonts.CalibriBold, fontSize - 2f, new RgbColor(0, 68, 105)));

            var requiredHeight = table.GetRequiredHeight();
            table.Height = requiredHeight;

            return table;
        }

        private Table AddIndicators(List<GovernanceIndicator> indicators, float width)
        {
            const float fontSize = 10f;
            const float rowHeight = 12f;

            var table = GetDefaultTable(0.0f, 0.0f, width, rowHeight);
            table.CellDefault.Border.Bottom.Width = 1.0f;
            table.CellDefault.Border.Bottom.LineStyle = LineStyle.Solid;
            table.CellDefault.Border.Bottom.Color = RgbColor.Black;

            table.Columns.Add(width*0.10f);
            table.Columns.Add(width*0.75f);
            table.Columns.Add(width*0.15f);

            var row = table.Rows.Add(rowHeight);
            row.Cells.Add(
                new Label(" ", 0.0f, 0.0f, width*0.10f,
                    fontSize + 2f, Fonts.CalibriBold, fontSize, TextAlign.Center));
            row.Cells.Add(
                new Label("Indicator", 0.0f, 0.0f, width*0.75f,
                    fontSize + 2f, Fonts.CalibriBold, fontSize));
            row.Cells.Add(
                new Label("Score", 0.0f, 0.0f, width * 0.15f,
                    fontSize + 2f, Fonts.CalibriBold, fontSize, TextAlign.Center));

            if (indicators.Any())
            {
                foreach (var indicator in indicators)
                {
                    row = table.Rows.Add(rowHeight);

                    row.Cells.Add(new Label(indicator.Number, 0.0f, 0.0f, width * 0.10f,
                            fontSize + 2f, Fonts.CalibriRegular, fontSize, TextAlign.Left));
                    row.Cells.Add(
                        new Label(indicator.Name, 0.0f, 0.0f, width * 0.75f,
                            fontSize + 2f, Fonts.CalibriRegular, fontSize));
                    row.Cells.Add(
                        new Label(indicator.Score.ToString(), 0.0f, 0.0f, width * 0.15f,
                            fontSize + 2f, Fonts.CalibriRegular, fontSize, TextAlign.Center));
                }
            }

            var requiredHeight = table.GetRequiredHeight();
            table.Height = requiredHeight;

            return table;
        }
    }
}
